package com.sfzd5.exam.helplibrary.recognition;

import android.graphics.Bitmap;
import android.util.Log;

import com.google.gson.Gson;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.sfzd5.exam.helplibrary.exam.ExamInof;
import com.sfzd5.exam.helplibrary.exam.MakePage;
import com.sfzd5.exam.helplibrary.exam.PageA4;
import com.sfzd5.exam.helplibrary.exam.PostAnserResult;
import com.sfzd5.exam.helplibrary.exam.answersheet.AnswerSheetQuestion;
import com.sfzd5.exam.helplibrary.exam.answersheet.Area;
import com.sfzd5.exam.helplibrary.exam.answersheet.BlankAnswerSheetQuestion;
import com.sfzd5.exam.helplibrary.exam.answersheet.ExpoundAnswerSheetQuestion;
import com.sfzd5.exam.helplibrary.exam.answersheet.ExpoundChildQuestion;

import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.Rect;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Recognition {

    double pageWidthRatio;
    File externalCacheDir;
    WorkProcess workProcess;
    ExamInof examInof;
    public Recognition(double pageWidthRatio, File externalCacheDir, WorkProcess workProcess){

        this.pageWidthRatio = pageWidthRatio;
        this.externalCacheDir = externalCacheDir;
        this.workProcess = workProcess;
        this.examInof = workProcess.getExamInof();
    }

    public Result parseInfoFromBitmap(Bitmap bitmap) {
        int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

        RGBLuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(),
                bitmap.getHeight(), pixels);
        GlobalHistogramBinarizer binarizer = new GlobalHistogramBinarizer(source);
        BinaryBitmap image = new BinaryBitmap(binarizer);
        Result result = null;
        try {
            result = new QRCodeReader().decode(image);
            return result;
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (ChecksumException e) {
            e.printStackTrace();
        } catch (FormatException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String rgQRCode(Bitmap bitmap) {
        Result result = parseInfoFromBitmap(bitmap);
        if (result != null) {
            return result.getText();
        } else {
            return "";
        }
    }

    public String takeQRCode(PageProcess pageProcess){
        int p = pageProcess.cameraPageMat.cols()/4;
        Rect rect = new Rect(p*3-1, 0, p, p);
        Mat qrMat = new Mat(pageProcess.cameraPageMat, rect);
        Bitmap img = MatBitmapConvert.mat2Bitmap(qrMat);
        return rgQRCode(img);
    }

    //各题分开保存图片，选择题识别一下
    //不用识别，直接用模板进行匹配切割

    /**
     * 最重要的地方，识别答题卡内容
     * @param bitmap
     * @param cameraWidth
     * @param cameraHeight
     * @return
     */
    public PostAnserResult PageRecognition(Bitmap bitmap, double cameraWidth, double cameraHeight) {
        //创建处理类
        PageProcess pageProcess = new PageProcess(bitmap, cameraWidth, cameraHeight, pageWidthRatio);

        //切出预览比例的有效区域
        pageProcess.cutPage();

        //二值化
        pageProcess.threshold();

        //模板匹配切出内容部分，四个标识点中间的部分
        pageProcess.takeMat();

        String qrCode = takeQRCode(pageProcess);
        QRCodeMessage qrCodeMessage = new Gson().fromJson(qrCode, QRCodeMessage.class);

        //查找轮廓
        List<Mat> mats = pageProcess.findQuestionArea();

        List<Tasksubmit> tasksubmitList = new ArrayList<>();
        if(mats.size() == examInof.areaList.size()){
            //针对题目切分行，选择题按行切，
            for(int i=0; i<examInof.areaList.size(); i++){
                Area area = examInof.areaList.get(i);
                Mat mat = mats.get(i);
                if(area.areaType == Area.AreaType.Choice){
                    tasksubmitList.addAll(createChoiceTasksubmit(mat, area));
                } else if(area.areaType == Area.AreaType.Blank){
                    tasksubmitList.addAll(createBlankTasksubmit(mat, area));
                } else if(area.areaType == Area.AreaType.Expound){
                    tasksubmitList.addAll(createExpoundTasksubmit(mat, area));
                }
            }
        }

        for(Tasksubmit t : tasksubmitList){
            t.student_id = qrCodeMessage.stuId;
            t.task_id = qrCodeMessage.taskId;
        }

        PostAnserResult examResult = new PostAnserResult();
        examResult.tasksubmits = tasksubmitList;
        return examResult;
        /*
        Mat minMat = null;

        examResult.pics = new ArrayList<>();

        String fn = String.valueOf(System.currentTimeMillis());
        for(int i=0; i<mats.size(); i++){
            Mat mat = mats.get(i);
            String fileName = fn + "_" + i + ".jpg";
            saveBmp(mat, fileName);
            examResult.pics.add(fileName);
            if(minMat==null)
                minMat = mat;
            else {
                if(mat.size().area()<minMat.size().area())
                    minMat = mat;
            }
        }

        if(minMat!=null){
            List<Mat> matList = OpenCVHelper.cutImgX(minMat);
            for(int i=1; i<3; i++){
                Mat optionLine = matList.get(i);
                String fileName = fn + "_op_" + i + ".jpg";
                saveBmp(optionLine, fileName);
                //识别选择题
                examResult.optionChecked += pageProcess.getCheckedInfo(optionLine) + "\n";
            }
        }

        return examResult;

        //saveBmp(pageProcess.pageMat, fn+"t.jpg");
        //saveBmp(pageProcess.binMat, fn+"b.jpg");
        //saveBmp(bitmap, fn+"y.jpg");



                        int frontImgWidth = imageView.getWidth();
                        int frontImgHeight = imageView.getHeight();
                        int bitmapWidth = bitmap.getWidth();
                        int bitmapHeight = bitmap.getHeight();
                        Size size = camera.getPreviewSize();
                        Size psize = camera.getPictureSize();
                        Size nsize = camera.getSnapshotSize();

                        String fn = String.valueOf(System.currentTimeMillis());
                        saveBmp(bitmap, fn+"y.jpg");

                        FrameLayout cameraFrame = (FrameLayout) findViewById(R.id.cameraFrame);
                        cameraFrame.setDrawingCacheEnabled(true);
                        cameraFrame.buildDrawingCache();
                        Bitmap cameraScreen = Bitmap.createBitmap(cameraFrame.getDrawingCache());
                        saveBmp(cameraScreen, fn+"c.jpg");
                        //目标将图片从中裁剪出来


                        //由屏幕象素转为拍照象素时的比例
                        float bl = (float)bitmap.getHeight()/(float)frontImgHeight;

                        float pageWidth = frontImgWidth * PageWidthRatio;
                        float pageHeight = frontImgHeight * PageWidthRatio;

                        if(pageWidth / pageHeight > PageA4.pageWidthm / PageA4.pageHeightm){
                            pageWidth = pageHeight * PageA4.pageWidthm / PageA4.pageHeightm;
                        } else {
                            pageHeight = pageWidth * PageA4.pageHeightm / PageA4.pageWidthm;
                        }

                        pageWidth *= bl;
                        pageHeight *= bl;
                        float top = (bitmap.getHeight() - pageHeight) / 2;
                        float left = (bitmap.getWidth() - pageWidth) / 2;

                        //裁剪
                        Bitmap bmp2 = Bitmap.createBitmap(
                                bitmap,
                                (int)left,
                                (int)top,
                                (int)pageWidth,
                                (int)pageHeight
                        );
                        //回收
                        bitmap.recycle();

                        saveBmp(bmp2, fn+"c.jpg");

                        float mmPoints = pageWidth / PageA4.mm2point(PageA4.pageWidthm);
                        float x = PageA4.mm2point(5)*mmPoints;
                        float y = PageA4.mm2point(10)*mmPoints;
                        float w = PageA4.mm2point(PageA4.pageWidthm - 10)*mmPoints;
                        float h = PageA4.mm2point(PageA4.pageHeightm - 20)*mmPoints;

                        Bitmap bmp = Bitmap.createBitmap(bmp2, (int)x, (int)y, (int)w, (int)h);

                        saveBmp(bmp, fn+"t.jpg");

                        bmp2.recycle();


        childHandler.post(new Runnable() {
            @Override
            public void run() {

                                WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
                                DisplayMetrics dm = new DisplayMetrics();
                                wm.getDefaultDisplay().getMetrics(dm);

                                int windowWidth = dm.widthPixels;
                                int windowHeight = dm.heightPixels;

                                sb.append("bitmapWidth:").append(bitmap.getWidth()).append("\r\n").append("bitmapHeight:").append(bitmap.getHeight()).append("\r\n");
                                sb.append("windowWidth:").append(windowWidth).append("\r\n").append("windowHeight:").append(windowHeight).append("\r\n");


                Intent result = new Intent();
                result.putExtra("pics", new Gson().toJson(examResult));
                setResult(RESULT_OK, result);
                finish();

            }
        });
        */
    }


    private void saveBmp(Mat src, String fileName){
        Bitmap bmp = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_4444);;
        Utils.matToBitmap(src, bmp); //convert mat to bitmap
        saveBmp(bmp, fileName);
    }

    private void saveBmp(Bitmap bmp, String fileName){

        // saveBitmap(bytes);//保存照片的处理
        File cache = externalCacheDir;
        File picFile = new File(cache, fileName);
        String picFilePath = picFile.getAbsolutePath();
        Log.i("Camera", picFilePath);
        try {
            FileOutputStream fos = new FileOutputStream(picFile);
            bmp.compress(Bitmap.CompressFormat.JPEG, 90, fos);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    private List<Tasksubmit> createExpoundTasksubmit(Mat mat, Area area){
        List<Tasksubmit> tasksubmits = new ArrayList<>();
        List<ExpoundAnswerSheetQuestion> expoundList = new ArrayList<>();
        for(AnswerSheetQuestion q : area.answerSheetQuestionList){
            expoundList.add(new ExpoundAnswerSheetQuestion(q));
        }
        for(int i=0; i<expoundList.size(); i++){
            ExpoundAnswerSheetQuestion q = expoundList.get(i);
            Tasksubmit tasksubmit = new Tasksubmit();
            int lineCount = 0;
            for(ExpoundChildQuestion cq : q.getChildQuestionList()){
                lineCount += cq.lineNum;
            }
            Mat tasksubmit_mat = cutLine(mat, PageA4.lineHightm, i, lineCount);
            //下面这两个可以从试卷上的二维码得出
            tasksubmit.student_id = 0;
            tasksubmit.task_id = 0;
            tasksubmit.question_id = q.questionId;
            //tasksubmit.answerBase64Pic = "";
            tasksubmit.answer = "";
            tasksubmit.answerBase64Pic = MatBitmapConvert.bitmapToBase64(MatBitmapConvert.mat2Bitmap(tasksubmit_mat));
            tasksubmit.isRight = false;
            tasksubmits.add(tasksubmit);
        }
        return tasksubmits;
    }


    private List<Tasksubmit> createBlankTasksubmit(Mat mat, Area area){
        List<Tasksubmit> tasksubmits = new ArrayList<>();
        List<BlankAnswerSheetQuestion> blankList = new ArrayList<>();
        for(AnswerSheetQuestion q : area.answerSheetQuestionList){
            blankList.add(new BlankAnswerSheetQuestion(q));
        }
        List<Integer> linesList = MakePage.getBlankLines(1, blankList);
        int idx = 0;
        for(int i=0; i<blankList.size(); i++){
            BlankAnswerSheetQuestion q = blankList.get(i);
            Tasksubmit tasksubmit = new Tasksubmit();
            Mat tasksubmit_mat = cutLine(mat, PageA4.lineHightm, idx, linesList.get(i));
            idx+=linesList.get(i);
            //下面这两个可以从试卷上的二维码得出
            tasksubmit.student_id = 0;
            tasksubmit.task_id = 0;
            tasksubmit.question_id = q.questionId;
            //tasksubmit.answerBase64Pic = "";
            tasksubmit.answer = "";
            tasksubmit.answerBase64Pic = MatBitmapConvert.bitmapToBase64(MatBitmapConvert.mat2Bitmap(tasksubmit_mat));
            tasksubmit.isRight = false;
            tasksubmits.add(tasksubmit);
        }
        return tasksubmits;
    }

    /**
     * 创建选择题答案
     * @param mat
     * @param area
     * @return
     */
    private List<Tasksubmit> createChoiceTasksubmit(Mat mat, Area area){
        //计算选择题的行数
        int lineCout = area.answerSheetQuestionList.size() / 4;
        if(area.answerSheetQuestionList.size() % 4 > 0) lineCout++;
        String[] options = {"A","B","C","D"};
        List<Tasksubmit> tasksubmits = new ArrayList<>();

        double wm = PageA4.contextWidthm() + 1.5;
        int w = mat.cols();
        double dpm = w / wm;

        List<Mat> mats = new ArrayList<>();
        for(int i=0; i<lineCout; i++){
            mats.add(cutLine(mat, PageA4.optionLineHeightm, i, 1));
        }
        for(int i=0; i<area.answerSheetQuestionList.size(); i++){
            AnswerSheetQuestion q = area.answerSheetQuestionList.get(i);
            Tasksubmit tasksubmit = new Tasksubmit();
            Mat tasksubmit_mat = cutChoiceQuestionAnswer(mats.get(i/4), i%4, dpm);
            //下面这两个可以从试卷上的二维码得出
            tasksubmit.student_id = 0;
            tasksubmit.task_id = 0;
            tasksubmit.question_id = q.questionId;
            //tasksubmit.answerBase64Pic = "";
            tasksubmit.answer = "";
            for(int j=0; j<4; j++){
                Rect rect = new Rect((int)(6*dpm + 7*j*dpm), 0, (int)(7*dpm), tasksubmit_mat.rows());
                int wmm = tasksubmit_mat.cols();
                int count = OpenCVHelper.countBlack(new Mat(tasksubmit_mat, rect));
                if(count>150){
                    tasksubmit.answer += options[j];
                }
            }
            tasksubmit.answerBase64Pic = MatBitmapConvert.bitmapToBase64(MatBitmapConvert.mat2Bitmap(tasksubmit_mat));
            tasksubmit.isRight = q.answer.endsWith(tasksubmit.answer);
            tasksubmits.add(tasksubmit);
        }
        return tasksubmits;
    }

    private Mat cutChoiceQuestionAnswer(Mat curMat, int i, double dpm){
        int p = 44 * i; //数字
        int w = curMat.cols();
        int h = curMat.rows();
        Rect rect = new Rect((int)(p*dpm), 0, (int)(28*dpm + 6*dpm), curMat.rows());
        return new Mat(curMat, rect);
    }

    private Mat cutLine(Mat curMat, double lineHeight, int lineIdx, int lineCount){
        double wm = PageA4.contextWidthm() + 1.5;
        int px = 3;
        int w = curMat.cols();
        int h = curMat.rows();
        double dpm = w / wm;
        Rect rect = new Rect((int)(dpm*3), (int)(dpm*(3+lineHeight*lineIdx)), w - (int)(dpm*6), (int)(dpm*lineHeight*lineCount));
        return new Mat(curMat, rect);
    }

}
